package interactiond

import (
	"github.com/pkg/errors"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

const (
	// Replay 评论标识
	Replay = "reply"
)

var (
	_ ReplayAggregateRoot = &replayAggregateRoot{}
)

func initReplay(d ddd.Domain, repo ReplayRepo) {
	car := &replayAggregateRoot{}
	car.Init(car, d, Replay)
	repo.Init(repo, car, Replay)
}

// ReplayAggregateRoot 评论聚合根
type ReplayAggregateRoot interface {
	ddd.AggregateRoot
	GetReplay(ctx ddd.Context, id string) (*ReplayAggregate, error)
	Replay(ctx ddd.Context, path ReplayPath, desc ReplayDesc) (id string, err error)
	QueryGroupReplayPage(ctx ddd.Context, igid string, s []RStatus, pi common.PageInfo) (pr common.PageResult, result []ReplayAggregate, err error)
	QueryGroupHostReplayPage(ctx ddd.Context, igid string) (result []ReplayAggregate, err error)
}
type replayAggregateRoot struct {
	ddd.BaseAggregateRoot
}

func (r *replayAggregateRoot) Replay(ctx ddd.Context, path ReplayPath, desc ReplayDesc) (id string, err error) {
	id, err = r.Repo().Replay(ctx, path, desc)
	if err == nil {
		reply, _ := r.GetReplay(ctx, id)
		r.Trigger(ctx, EvtTypReplay, EvtActReplay, reply)
	}
	return
}

// Repo 获取聚合对应的仓储
func (r *replayAggregateRoot) Repo() ReplayRepo {
	return r.Repository().(ReplayRepo)
}
func (r *replayAggregateRoot) GetReplay(ctx ddd.Context, id string) (*ReplayAggregate, error) {
	return r.Repo().GetReplay(ctx, id)
}
func (r *replayAggregateRoot) QueryGroupReplayPage(ctx ddd.Context, igid string, s []RStatus, pi common.PageInfo) (pr common.PageResult, result []ReplayAggregate, err error) {
	return r.Repo().QueryGroupReplayPage(ctx, igid, s, pi)
}
func (r *replayAggregateRoot) QueryGroupHostReplayPage(ctx ddd.Context, igid string) (result []ReplayAggregate, err error) {
	return r.Repo().QueryGroupHostReplayPage(ctx, igid, 3)
}

// ReplayRepo 评论仓储
type ReplayRepo interface {
	ddd.Repository
	Replay(ctx ddd.Context, path ReplayPath, desc ReplayDesc) (id string, err error)
	GetReplay(ctx ddd.Context, id string) (*ReplayAggregate, error)
	Delete(ctx ddd.Context, id string) error
	CheckOk(ctx ddd.Context, id string, rchk ReplayCheck) error
	CheckNo(ctx ddd.Context, id string, rchk ReplayCheck) error
	Destroy(ctx ddd.Context, id string) error
	QueryChildrenPage(ctx ddd.Context, id string, pi common.PageInfo) (pr common.PageResult, result []ReplayAggregate, err error)
	QueryGroupReplayPage(ctx ddd.Context, igid string, s []RStatus, pi common.PageInfo) (pr common.PageResult, result []ReplayAggregate, err error)
	QueryGroupHostReplayPage(ctx ddd.Context, igid string, num int) (result []ReplayAggregate, err error)
	AddReplayNum(ctx ddd.Context, id string, num int) error
	AddLikeNum(ctx ddd.Context, id string, num int) error
}

// ReplayAggregate 评论聚合
type ReplayAggregate struct {
	ddd.BaseAggregate
	ReplayID        string `json:"replay_id"` // 评论ID
	ReplayPath      `json:"path"`
	ReplayDesc      `json:"desc"`
	ChildReplyTotal `json:"child_total"`
	ReplayCheck     `json:"check"`
	Operator        `json:"operator"`
}

func (a *ReplayAggregate) handlerEvtActData(ctx ddd.Context, evtact string, handler func() error) error {
	edata := &EvtActReplayOPData{
		Old: *a,
	}
	err := handler()
	if err != nil {
		return err
	}
	edata.New, err = a.Repo().GetReplay(ctx, a.ReplayID)
	if err != nil {
		log.Warnf("更新完成后获取信息失败：%v", err)
		return nil
	}
	a.Trigger(ctx, EvtTypReplay, evtact, edata)
	return err
}

// Repo 获取聚合对应的仓储
func (a *ReplayAggregate) Repo() ReplayRepo {
	return a.Repository().(ReplayRepo)
}

// Replay 针对评论进行评论
// 发出添加评论事件
func (a *ReplayAggregate) Replay(ctx ddd.Context, desc ReplayDesc) (id string, err error) {
	path := ReplayPath{
		IGID:     a.IGID,
		ParentID: a.ReplayID,
	}
	id, err = a.Repo().Replay(ctx, path, desc)
	if err == nil {
		if r, err := a.Repo().GetReplay(ctx, id); err == nil {

			a.Trigger(ctx, EvtTypReplay, EvtActReplay, r)
		} else {
			return "", err
		}
	}
	return
}

// Delete 删除评论
// 标记删除
// 发出删除评论事件
// 子评论可以在定期清理时删除
func (a *ReplayAggregate) Delete(ctx ddd.Context) (err error) {
	if a.Status == RStatusDel {
		return
	}
	return a.handlerEvtActData(ctx, EvtActDelete, func() error {
		return a.Repo().Delete(ctx, a.ReplayID)
	})
}

// Destroy 销毁评论
// 彻底删除
// 发出彻底删除事件
func (a *ReplayAggregate) Destroy(ctx ddd.Context) (err error) {
	if a.Status != RStatusDel {
		return errors.New("评论不是删除状态不能进行彻底删除")
	}
	return a.handlerEvtActData(ctx, EvtActDestroy, func() error {
		return a.Repo().Destroy(ctx, a.ReplayID)
	})
}

// CheckOK 审核评论通过
// ok true 审核通过 false 审核失败
// 发出评论通过审核事件
func (a *ReplayAggregate) CheckOK(ctx ddd.Context, rchk ReplayCheck) (err error) {
	if a.Status != RStatusDel {
		return errors.New("评论不是删除状态不能进行彻底删除")
	}
	return a.handlerEvtActData(ctx, EvtActCheckOk, func() error {
		return a.Repo().CheckOk(ctx, a.ReplayID, rchk)
	})
}

// CheckNo 审核评论不通过
// 发出评论未通过审核事件
func (a *ReplayAggregate) CheckNo(ctx ddd.Context, rchk ReplayCheck) (err error) {
	return a.handlerEvtActData(ctx, EvtActCheckNo, func() error {
		return a.Repo().CheckOk(ctx, a.ReplayID, rchk)
	})
}

// QueryChildrenPage 分页获取当前评论的子评论列表
func (a *ReplayAggregate) QueryChildrenPage(ctx ddd.Context, pi common.PageInfo) (pr common.PageResult, result []ReplayAggregate, err error) {
	return a.Repo().QueryChildrenPage(ctx, a.ReplayID, pi)
}

// AddReplayNum 增加子评论数量
func (a *ReplayAggregate) AddReplayNum(ctx ddd.Context, num int) error {
	return a.Repo().AddReplayNum(ctx, a.ReplayID, num)
}

// AddLikeNum 增加评论点赞数量
func (a *ReplayAggregate) AddLikeNum(ctx ddd.Context, num int) error {
	return a.Repo().AddLikeNum(ctx, a.ReplayID, num)
}

// AddListenerForReply 监听评论
func AddListenerForReply(handler func(ctx ddd.Context, evt ddd.Event, reply *ReplayAggregate) error) {
	ddd.AddEventListener(EvtTypReplay, EvtActReplay, ddd.CreEventListener(func(ctx ddd.Context, evt ddd.Event) error {

		if reply, ok := evt.Data.(*ReplayAggregate); ok {
			return handler(ctx, evt, reply)
		}
		return nil
	}))
}
